#include "NSocket.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#ifdef WIN32
BOOL CNSocket::m_iInstanceCnt = FALSE;
#endif

CNSocket::CNSocket()
{
    m_Socket = ERROR_SOCKET_NULL;

#ifdef WIN32
    WSADATA   m_WsaData;
    int		  iRet;
    if (m_iInstanceCnt == 0)
    {
        iRet = WSAStartup( MAKEWORD(2,2), &m_WsaData );
        if ( iRet != NO_ERROR )
        {
            ReportError("Error at WSAStartup()\n");
        }
    }
    m_iInstanceCnt ++;
#endif

}

CNSocket::CNSocket(SOCKET s)
{
	m_Socket = s;
}

CNSocket::~CNSocket()
{
	if (m_Socket != INVALID_SOCKET)
	{
		Close();
	}

#ifdef WIN32
	m_iInstanceCnt --;
	if (m_iInstanceCnt == 0)
	{
		WSACleanup();
	}
#endif
}

CNSocket CNSocket::Accept()
{
    CNSocket NewSock = accept(m_Socket,NULL,NULL);
    return NewSock;
}


CNSocket CNSocket::Accept(CNSOCKADDR * addr /* = NULL */,socklen_t * addrlen /* = NULL */)
{
//////////////////////////////////////////////////////////////////////////
//TODO:accept
    CNSocket NewSock = accept(m_Socket,addr,addrlen);
    return NewSock;
}

int CNSocket::Bind(const char *pszIpAddr, int iPort,int af)
{
//////////////////////////////////////////////////////////////////////////
//TODO:bind
	int iRet = SOCKET_ERROR;
	CNSOCKADDR_IN SockAddr;//INADDR_ANY
	SockAddr.sin_family = af;
	SockAddr.sin_port = htons(iPort);
	if (pszIpAddr != NULL)
	{
		SockAddr.sin_addr.s_addr = inet_addr(pszIpAddr);
	}
	else
	{
		SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	}
	iRet = bind(m_Socket,(CNSOCKADDR *)&SockAddr,sizeof(SockAddr));
    return iRet;
}

int CNSocket::Connect(const char *szURL, int iPort)
{

    BOOL bRet = FALSE;
    int  iRet = SOCKET_ERROR;
    char szIPAddr[MAX_IP_LEN] = {0};

    if (strstr(szURL,"http://") != NULL)
    {
        bRet = GetIpAddrFromUrl(szURL,szIPAddr,sizeof(szIPAddr));
    }
    else
    {
        strcpy(szIPAddr,szURL);
        bRet = SOCKET_OK;
    }

    if (bRet != SOCKET_OK)
    {
        ReportError("Error at Get Ip !");
        return SOCKET_ERROR;
    }

    CNSOCKADDR_IN ClientService;
    ClientService.sin_family = AF_INET;
    ClientService.sin_addr.s_addr = inet_addr(szIPAddr);
    ClientService.sin_port = htons( iPort );

    iRet = connect( m_Socket, (CNSOCKADDR *) &ClientService, sizeof(ClientService) );

    if ( iRet == SOCKET_ERROR)
    {
        ReportError( "Failed to connect" );
        return ERROR_CONNECT_FAIL;
    }

    return SOCKET_OK;
}



BOOL CNSocket::GetIpAddrFromUrl(const char *lpURL, char *lpRetBuffer, UINT iRetBuffLen)
{
    CNHOSTENT  *pHost = NULL;
    char	   *pszUrlToFind = NULL;

    pszUrlToFind = (char *)malloc(strlen(lpURL)+1);
    char *pChrPos   = pszUrlToFind;
    char *pDealStr	= pszUrlToFind;

    strcpy(pszUrlToFind,lpURL);

    if (strstr(pszUrlToFind,"http://"))
    {
        pDealStr += strlen("http://");
    }

    pChrPos = strchr(pDealStr,'/');
    if(pChrPos != NULL)
        *pChrPos = '\0';

    pChrPos = strchr(pDealStr,':');
    if(pChrPos != NULL)
        *pChrPos = '\0';

    pHost = gethostbyname(pDealStr);

    free(pszUrlToFind);
    if(pHost == NULL)
    {
		ReportError("ERROR_GET_HOSTNAME_FAIL");
        return ERROR_GET_HOSTNAME_FAIL;
    }

#ifdef WIN32

    in_addr		Addr;
    char	   *pszIpAddr;
    char	   *pHostList;

	pHostList = *pHost->h_addr_list;
	if(pHostList == NULL)
	{
		return ERROR_GET_HOSTNAME_FAIL;
	}

	memcpy(&Addr.S_un.S_addr,pHostList,pHost->h_length);
	pszIpAddr = inet_ntoa(Addr);
	if(strlen(pszIpAddr) < iRetBuffLen)
	{
		sprintf(lpRetBuffer,"%s",pszIpAddr);
	}
	else
	{
		ReportError("ERROR: ERROR_BUFFER_NOT_ENOUGH\n");
		return ERROR_BUFFER_NOT_ENOUGH;
	}

#else
    inet_ntop(pHost->h_addrtype, *pHost->h_addr_list, lpRetBuffer, iRetBuffLen);
#endif
    return SOCKET_OK;
}

int CNSocket::Send(const char *pSendBuf, int iLen)
{
    int iRet = 0;
    iRet = send(m_Socket,pSendBuf,iLen,0);
    return iRet;
}

int CNSocket::Recv(char *pBuf, int iLen)
{
    int iRecv = recv( m_Socket, pBuf, iLen, 0 );
    return iRecv;
}

void CNSocket::ReportError(const char *szMsg)
{

#ifdef _CONSOLE

    cerr<<szMsg<<endl;

#else
#ifdef WIN32

    MessageBox(0,szMsg,"Msg",MB_ICONWARNING);

#endif

#endif

}

void CNSocket::Close()
{
#ifdef WIN32
    closesocket(m_Socket);
#else
    close(m_Socket);
#endif
	m_Socket = INVALID_SOCKET;
}

int CNSocket::Listen(int iMaxWaitQueue)
{
    int iRet = 0;
	listen(m_Socket,iMaxWaitQueue);
    return iRet;
}


CNSocket & CNSocket::operator =(const CNSocket &Socket)
{
	m_Socket = Socket.m_Socket;
	return *this;
}

CNSocket & CNSocket::operator =(const SOCKET &Socket)
{
	m_Socket = Socket;
	return *this;
}


CNSocket::operator SOCKET()
{
	return m_Socket;
}

CNSocket &CNSocket::operator =(int iStateCode)
{
	m_Socket = (SOCKET)iStateCode;
	return *this;
}




void CNSocket::SocketCreate(int af ,int type ,int protocol)
{
	m_Socket = socket(af,type,protocol);
	if ( m_Socket == INVALID_SOCKET )
    {
        ReportError( "Error at NewSocket()");
    }
}

//http://www.cppblog.com/killsound/archive/2009/01/16/72138.html
int CNSocket::SetSockOpt(int level, int optname, const char *optval, int optlen)
{
	return setsockopt(m_Socket,level,optname,optval,optlen);
}
